<template>
  <div class="dashboard-container">
    <div class="app-container">
      <ElTabs @tab-click="onTabClick">
        <ElTabPane label="角色管理" ref="roleTabPane">
          <ElButton
            icon="el-icon-video-camera-solid"
            type="primary"
            size="small"
            @click="dialogs.addRole.visible = true"
            style="margin-bottom: 15px"
          >
            添加角色
          </ElButton>

          <ElTable border :data="list">
            <ElTableColumn label="序号" type="index" width="120" />
            <ElTableColumn label="角色" prop="name" width="240" />
            <ElTableColumn label="描述" prop="description" />
            <ElTableColumn label="操作">
              <!-- row 就是上面绑定在 ElTable 组件上的 (:data="list") list 数组中的 一个对象 -->
              <!--                                  —— ElementUI 的 ElTable 和 ElTableColumn 组件就是这么封装的 -->
              <template #default="{ row }">
                <ElButton type="text" @click="dialogs.assignPerm.methods.open(row)" :loading="row.loadingOfAssignPerm"
                  >分配权限</ElButton
                >
                <ElButton type="text" @click="edit(row)">编辑</ElButton>
                <ElButton type="text" style="color: red" @click="delOfLoading(row)">删除</ElButton>
              </template>
            </ElTableColumn>
          </ElTable>
          <div style="margin-top: 15px; display: flex; justify-content: end; align-items: center">
            <ElPagination
              :page-sizes="[2, 5, 10, 20, 50]"
              :pageSize.sync="page.pagesize"
              layout="total, sizes, prev, pager, next, jumper"
              :total="page.total"
              :currentPage.sync="page.page"
              @current-change="getRoleList"
              @size-change="getRoleList"
            />
            <i class="el-icon-refresh" style="cursor: pointer; margin-left: 15px" @click="getRoleList"></i>
          </div>
        </ElTabPane>
        <ElTabPane label="公司信息">
          <ElAlert
            title="对公司名称、公司地址、营业执照、公司地区的更新，将使得公司资料被重新审核，请谨慎修改"
            type="info"
            show-icon
            :closable="false"
          />
          <ElForm ref="form" labelWidth="120px" style="margin-top: 50px">
            <ElFormItem label="公司名称">
              <ElInput v-model="formData.name" disabled style="width: 400px" />
            </ElFormItem>
            <ElFormItem label="公司地址">
              <ElInput v-model="formData.companyAddress" disabled style="width: 400px" />
            </ElFormItem>
            <ElFormItem label="公司电话">
              <ElInput v-model="formData.companyPhone" disabled style="width: 400px" />
            </ElFormItem>
            <ElFormItem label="公司邮箱">
              <ElInput v-model="formData.mailbox" disabled style="width: 400px" />
            </ElFormItem>
            <ElFormItem label="备注">
              <ElInput v-model="formData.remarks" disabled style="width: 400px" type="textarea" rows="3" />
            </ElFormItem>
          </ElForm>
        </ElTabPane>
      </ElTabs>
    </div>

    <!-- 对话框 放到这里最安全（因为有可能显示不出来），因为 对话框本身 就是一个独立的 显示区域，和其他 元素 不相干 -->

    <!-- 编辑角色对话框 -->
    <ElDialog
      :title="dialogs.editRole.title"
      :visible.sync="dialogs.editRole.visible"
      @closed="dialogs.editRole.methods.onClosed"
    >
      <!-- 
        注意：el-dialog 组件的内容是懒渲染的，只有当弹层显示出来后，才会加载其内容，
        并且，内容有缓存，当对话框一旦显示出来后，关闭时，内容不会销毁，下次再打开，内容不会重新创建，直接用缓存的
       -->

      <!-- 这个组件为了 验证上面的 注意事项描述，在频繁显示/隐藏对话框时，请观察这个组件中的 created 钩子会执行多少次 -->
      <DggHeHe />

      <ElForm
        ref="editRoleForm"
        :model="dialogs.editRole.form.data"
        :rules="dialogs.editRole.form.rules"
        label-width="120px"
      >
        <ElFormItem label="角色名称" prop="name">
          <ElInput v-model="dialogs.editRole.form.data.name" />
        </ElFormItem>
        <ElFormItem label="角色描述" prop="description">
          <ElInput v-model="dialogs.editRole.form.data.description" />
        </ElFormItem>
        <ElFormItem>
          <ElButton size="small" type="primary" @click="dialogs.editRole.methods.onOk">确定</ElButton>
          <ElButton size="small" @click="dialogs.editRole.visible = false">取消</ElButton>
        </ElFormItem>
      </ElForm>
    </ElDialog>

    <!-- 添加角色对话框 -->
    <ElDialog :title="dialogs.addRole.title" :visible.sync="dialogs.addRole.visible">
      <ElForm
        ref="addRoleForm"
        :model="dialogs.addRole.form.data"
        :rules="dialogs.addRole.form.rules"
        label-width="120px"
      >
        <ElFormItem label="角色名称" prop="name">
          <ElInput v-model="dialogs.addRole.form.data.name" />
        </ElFormItem>
        <ElFormItem label="角色描述" prop="description">
          <ElInput v-model="dialogs.addRole.form.data.description" />
        </ElFormItem>
        <ElFormItem>
          <ElButton size="small" type="primary" @click="dialogs.addRole.methods.onOk">确定</ElButton>
          <ElButton size="small" @click="dialogs.addRole.visible = false">取消</ElButton>
        </ElFormItem>
      </ElForm>
    </ElDialog>

    <!-- 分配权限对话框 -->
    <ElDialog
      :title="dialogs.assignPerm.title"
      :visible.sync="dialogs.assignPerm.visible"
      @closed="dialogs.assignPerm.methods.closed"
    >
      <ElForm>
        <ElFormItem>
          <ElTree
            ref="treePerm"
            :data="dialogs.assignPerm.form.data.list"
            :props="{ label: 'name', children: 'children' }"
            node-key="id"
            show-checkbox
            default-expand-all
            check-strictly
            :default-checked-keys="dialogs.assignPerm.defaultCheckedKeys"
          />
        </ElFormItem>
        <ElFormItem style="display: flex; justify-content: center">
          <ElButton type="primary" :loading="dialogs.assignPerm.loading" @click="dialogs.assignPerm.methods.ok"
            >确定</ElButton
          >
          <ElButton @click="dialogs.assignPerm.visible = false">取消</ElButton>
        </ElFormItem>
      </ElForm>
    </ElDialog>
  </div>
</template>

<script>
import axios from 'axios';
import DggHeHe from './DggHeHe';
import { getRoleList, getCompanyInfo, deleteRole, getRoleDetail, updateRole, addRole, assignPerm } from '@/api/setting';
import { getPermissionList } from '@/api/permission';
import { tranListToTreeDataByGroup } from '@/utils';
export default {
  name: 'Setting',
  components: { DggHeHe },
  data() {
    return {
      formData: {},
      list: [],
      page: {
        page: 1,
        pagesize: 10,
        total: 0,
      },
      dialogs: {
        assignPerm: {
          title: '分配权限',
          visible: false,
          loading: false, // 是否正在加载中
          curRow: null, // 当前操作的行（角色）数据
          defaultCheckedKeys: [],
          form: {
            data: {
              list: [], // 可选的权限列表
            },
          },
          methods: {
            ok: async () => {
              this.dialogs.assignPerm.loading = true;
              try {
                const permIds = this.$refs.treePerm.getCheckedKeys();
                await assignPerm({ id: this.dialogs.assignPerm.curRow.id, permIds });
                this.$message.success('权限分配成功');
                this.dialogs.assignPerm.visible = false;
              } finally {
                this.dialogs.assignPerm.loading = false;
              }
            },
            closed: () => {
              // 在关闭后，必须重置默认选中的key，因为 el-tree 在重新给 defaultCheckedKeys 赋值时，内部只会追加，不会清除上一次的选中节点
              this.$refs.treePerm.setCheckedKeys([]);
              // this.dialogs.assignPerm.defaultCheckedKeys = [];
            },
            open: async row => {
              row.loadingOfAssignPerm = true;

              this.dialogs.assignPerm.curRow = row;

              this.dialogs.assignPerm.title = `为 "${row.name}" 分配权限`;

              try {
                const list = await getPermissionList();
                this.dialogs.assignPerm.form.data.list = tranListToTreeDataByGroup(list, 'pid', '0');

                const { permIds } = await getRoleDetail(row.id);
                this.dialogs.assignPerm.defaultCheckedKeys = permIds;

                this.dialogs.assignPerm.visible = true;
              } finally {
                row.loadingOfAssignPerm = false;
              }
            },
          },
        },
        addRole: {
          title: '添加角色',
          visible: false,
          form: {
            data: { name: '', description: '' },
            rules: {
              name: [{ required: true, message: '角色名称不能为空' }],
            },
          },
          methods: {
            onOk: async () => {
              await this.$refs.addRoleForm.validate();
              await addRole(this.dialogs.addRole.form.data, {
                target: this.$refs.addRoleForm.$el,
              });
              this.dialogs.addRole.visible = false;
              this.$message.success('新增成功');
              this.$refs.addRoleForm.resetFields();
              await this.getRoleList();
            },
          },
        },
        editRole: {
          title: '编辑角色',
          visible: false,
          form: {
            data: { name: '', description: '' },
            rules: {
              name: [{ required: true, message: '角色名称不能为空' }],
            },
          },
          methods: {
            onOk: async () => {
              await this.$refs.editRoleForm.validate();
              // 验证通过，走下来
              await updateRole(this.dialogs.editRole.form.data, {
                target: this.$refs.editRoleForm.$el,
              });
              // 关闭对话框
              this.dialogs.editRole.visible = false;
              // 更新成功，给个提示
              this.$message.success('更新成功');
              // 刷新列表
              await this.getRoleList();
            },
            // 为了保证事件处理函数中的 this 指向页面的组件实例，所以，这里要用箭头函数
            onClosed: () => {
              this.$refs.editRoleForm.resetFields();
            },
          },
        },
      },
    };
  },
  methods: {
    async edit(row) {
      this.dialogs.editRole.visible = true;
      await this.$nextTick();
      this.dialogs.editRole.form.data = await getRoleDetail(row.id, { target: this.$refs.editRoleForm.$el });
    },
    async delOfLoading(row) {
      // const CancelToken = axios.CancelToken;
      // let cancel;
      const source = axios.CancelToken.source();

      await this.$confirm(`你确定要删除 "${row.name}" 吗？`, '提示', {
        type: 'warning',
        // 是否将取消（点击取消按钮）与关闭（点击关闭按钮或遮罩层、按下 ESC 键）进行区分
        distinguishCancelAndClose: true,
        // action: 用户点击的什么？ confirm: 确定, cancel: 取消, close: 关闭
        // instance: instance 为 MessageBox 实例，可以通过它访问实例上的属性和方法
        // done: done 用于关闭 MessageBox 实例
        beforeClose: async (action, instance, done) => {
          console.log(action, 'action');
          // // 如果写在这里，不管点确定还是取消都会进来，那么就都会重新初始化局部变量，两次点击使用的变量的值不是同一个
          // const CancelToken = axios.CancelToken;
          // let cancel;
          if (action === 'confirm') {
            instance.confirmButtonText = '删除中...';
            instance.confirmButtonLoading = true;
            try {
              await deleteRole(row.id, source.token);
              // await deleteRole(row.id, new CancelToken(c => (cancel = c)));
            } catch (err) {
              // 这里一定要写 catch 否则，下面的代码还是会执行
              return;
            } finally {
              setTimeout(() => {
                instance.confirmButtonText = '确定';
                instance.confirmButtonLoading = false;
              }, 300);
            }

            done();

            // await deleteRole(row.id);
            this.$message.success('删除成功');

            // 如果这次删除的 是最后一条数据 并且 当前页 不是第1页 那么 就应该将 当前页码 -1 再去获取列表数据
            if (this.list.length === 1 && this.page.page !== 1) {
              this.page.page--;
            }

            await this.getRoleList();
          } else if (action === 'cancel') {
            source.cancel('你取消了删除操作哟~');
            // cancel && cancel('你取消了删除操作哟~');
            done();
          } else if (action === 'close') {
            // 如果做了 distinguishCancelAndClose: true，done 也是让 $confirm 异常
            done();
          }
        },
      });
    },
    async del(row) {
      await this.$confirm(`你确定要删除 "${row.name}" 吗？`, '提示', {
        type: 'warning',
      });
      await deleteRole(row.id);
      this.$message.success('删除成功');

      // 如果这次删除的 是最后一条数据 并且 当前页 不是第1页 那么 就应该将 当前页码 -1 再去获取列表数据
      if (this.list.length === 1 && this.page.page !== 1) {
        this.page.page--;
      }

      await this.getRoleList();
    },
    async onTabClick(tab) {
      // 点的是公司信息
      if (tab.index === '1') {
        // 去加载公司信息
        await this.getCompanyInfo();
      }
    },
    async getCompanyInfo() {
      this.formData = await getCompanyInfo(this.$store.state.user.userInfo.base.companyId, {
        target: this.$refs.form.$el, // 转圈圈的容器（DOM）
      });
    },
    async getRoleList() {
      // 加载中配置对象
      const loadingOptions = {
        target: this.$refs.roleTabPane?.$el, // 转圈圈的目标容器 DOM 对象
        spinner: 'el-icon-loading', // 自定义的转圈图标，不配就是默认的转圈圈图标
        text: '拼命加载中...', // 图标下方的加载中文案
        background: 'rgba(0, 0, 0, 0.8)', // 遮罩层背景色，支持 rgba
      };
      const { total, rows } = await getRoleList(this.page, loadingOptions);
      this.page.total = total;

      for (const v of rows) {
        v.loadingOfAssignPerm = false;
      }

      this.list = rows;
    },
  },
  async mounted() {
    await this.getRoleList();
  },
};
</script>
